#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/tty.h>

void n_tty_receive_buf(struct tty_struct *tty, const unsigned char *cp,
			      char *fp, int count)
{
	const unsigned char *p;
	char *f;
	int	i;
	char	buf[64];

	if (!tty->read_buf)
		return;

	if (tty->real_raw) {
		// spin_lock_irqsave(&tty->read_lock, cpuflags);
		i = min(N_TTY_BUF_SIZE - tty->read_cnt,
			N_TTY_BUF_SIZE - tty->read_head);
		i = min(count, i);
		memcpy(tty->read_buf + tty->read_head, cp, i);
		tty->read_head = (tty->read_head + i) & (N_TTY_BUF_SIZE-1);
		tty->read_cnt += i;
		cp += i;
		count -= i;

		i = min(N_TTY_BUF_SIZE - tty->read_cnt,
			N_TTY_BUF_SIZE - tty->read_head);
		i = min(count, i);
		memcpy(tty->read_buf + tty->read_head, cp, i);
		tty->read_head = (tty->read_head + i) & (N_TTY_BUF_SIZE-1);
		tty->read_cnt += i;
	
		// printf("this is %s(): %d  tty->read_cnt = %d\r\n", __func__, __LINE__, tty->read_cnt);
		// spin_unlock_irqrestore(&tty->read_lock, cpuflags);
	} else {
		// for (i = count, p = cp, f = fp; i; i--, p++) {
		// 	n_tty_receive_char(tty, *p);
		// }
	}
}

static inline int input_available_p(struct tty_struct *tty, int amt)
{
	tty_flush_to_ldisc(tty);
	if (tty->read_cnt >= (amt ? amt : 1))
		return 1;

	return 0;
}

/**
 *	n_tty_read		-	read function for tty
 *	@tty: tty device
 *	@file: file object
 *	@buf: userspace buffer pointer
 *	@nr: size of I/O
 *
 *	Perform reads for the line discipline. We are guaranteed that the
 *	line discipline will not be closed under us but we may get multiple
 *	parallel readers and must handle this ourselves. We may also get
 *	a hangup. Always called in user context, may sleep.
 *
 *	This code must be sure never to sleep through a hangup.
 */
#include <linux/signal.h>

unsigned char n_tty_read(struct tty_struct *tty)
{
	int c;
	int nr = 1;

do_it_again:
	while (nr) {
		/* This statement must be first before checking for input
		   so that any interrupt will set the state back to
		   TASK_RUNNING. */
		// set_current_state(TASK_INTERRUPTIBLE);

		if (!input_available_p(tty, 0)) {
			delayms(10);
			// schedule();
			// if (signal_pending(current)) {
			// 	retval = -ERESTARTSYS;
			// 	break;
			// }
			continue;
		}
		// __set_current_state(TASK_RUNNING);

		/* N.B. avoid overrun if nr == 0 */
		while (nr && tty->read_cnt) {
			c = tty->read_buf[tty->read_tail];
			tty->read_tail = ((tty->read_tail+1) & (N_TTY_BUF_SIZE-1));
			tty->read_cnt--;

			if (c == 'C')
				send_signal(6, SIGINT);
			// if (tty_put_user(tty, c, b++)) {
			// 	retval = -EFAULT;
			// 	b--;
			// 	break;
			// }
			// printf("this is %s(): %d   c = %c\r\n", __func__, __LINE__, c);
			nr--;
		}
	}

	// __set_current_state(TASK_RUNNING);
	return c;
}
